package admin

import (
	"beego/models"
	"beego/models/admin"
	"container/list"
	"encoding/json"
	"github.com/astaxie/beego"
	"github.com/gorilla/websocket"
	"net/http"
	"time"
)

type NetworkController struct {
	admin.BaseController
}

func init() {
	go chatroom()
}

var (
	subscribe   = make(chan Subscriber, 10) //订阅
	unsubscribe = make(chan string, 10)     //取消订阅
	publish     = make(chan Message, 10)    //发布 发表
	subscribers = list.New()                //订阅者
)

type Message struct {
	Type      int    `json:"type"`
	User      string `json:"user"`
	Timestamp int    `json:"timestamp"`
	Content   string `json:"content"`
}

type Subscriber struct {
	Name string
	Conn *websocket.Conn
}

func (c *NetworkController) Get() {
	//c.Ctx.WriteString("11111111111")
	c.TplName = "admin/network/index.html"
}

func SendMessage(types int, user string, msg string) Message {
	return Message{types, user, int(time.Now().Unix()), msg}
}

func (c *NetworkController) Join() {
	//username := c.GetString("username")
	username := models.GetDate()
	ws, err := websocket.Upgrade(c.Ctx.ResponseWriter, c.Ctx.Request, nil, 1024, 1024)
	if _, ok := err.(websocket.HandshakeError); ok {
		http.Error(c.Ctx.ResponseWriter, "Not a websocket handshake", 400)
		return
	} else if err != nil {
		http.Error(c.Ctx.ResponseWriter, "Cannot setup WebSocket connection", 500)
		return
	}

	subscribe <- Subscriber{Name: username, Conn: ws}

	//发生异常时，通知关闭该用户
	defer func() {
		unsubscribe <- username
	}()

	for {
		//开启监听已连接的用户
		_, p, err := ws.ReadMessage()
		if err != nil {
			return
		}
		publish <- SendMessage(2, username, string(p))
	}
}

func broadcastWebSocket(msg Message) {
	data, err := json.Marshal(msg)
	if err != nil {
		beego.Error("Fail to marshal event:", err)
		return
	}

	for sub := subscribers.Front(); sub != nil; sub = sub.Next() {
		ws := sub.Value.(Subscriber).Conn
		if ws != nil {
			if ws.WriteMessage(websocket.TextMessage, data) != nil {
				unsubscribe <- sub.Value.(Subscriber).Name //通知关闭该用户
			}
		}
	}
}

func isUserExist(subscribers *list.List, user string) bool {
	for sub := subscribers.Front(); sub != nil; sub = sub.Next() {
		if sub.Value.(Subscriber).Name == user {
			return true
		}
	}
	return false
}

func chatroom() {
	for {
		select {
		case sub := <-subscribe:
			if !isUserExist(subscribers, sub.Name) {
				subscribers.PushBack(sub)
				publish <- SendMessage(0, sub.Name, "连接成功")
			}

		case message := <-publish:
			broadcastWebSocket(message)

		case unsub := <-unsubscribe:
			for sub := subscribers.Front(); sub != nil; sub = sub.Next() {
				if sub.Value.(Subscriber).Name == unsub {
					subscribers.Remove(sub)
					ws := sub.Value.(Subscriber).Conn
					if ws != nil {
						if err := ws.Close(); err != nil {
							beego.Info("ws关闭失败")
						}
					}
					publish <- SendMessage(1, unsub, "关闭连接")
					break
				}
			}
		}
	}
}
